package cn.turboinfo.dongying.api.provider.common.service.impl.rule;

import cn.turboinfo.dongying.api.domain.common.service.rule.RuleGroupRelService;
import cn.turboinfo.dongying.api.domain.common.service.rule.RuleGroupService;
import cn.turboinfo.dongying.api.entity.common.enumeration.common.EntityObjectType;
import cn.turboinfo.dongying.api.entity.common.exception.common.DataAlreadyExistException;
import cn.turboinfo.dongying.api.entity.common.exception.rule.RuleException;
import cn.turboinfo.dongying.api.entity.common.pojo.rule.RuleGroup;
import cn.turboinfo.dongying.api.entity.common.pojo.rule.RuleGroupCreator;
import cn.turboinfo.dongying.api.entity.common.pojo.rule.RuleGroupRel;
import cn.turboinfo.dongying.api.entity.common.pojo.rule.RuleGroupUpdater;
import cn.turboinfo.dongying.api.provider.common.repository.database.rule.RuleGroupDAO;
import cn.turboinfo.dongying.api.provider.common.repository.database.rule.RuleGroupPO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sunshow.toolkit.core.qbean.helper.component.request.QBeanCreatorHelper;
import net.sunshow.toolkit.core.qbean.helper.component.request.QBeanUpdaterHelper;
import net.sunshow.toolkit.core.qbean.helper.service.impl.AbstractQServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RequiredArgsConstructor
@Service
public class RuleGroupServiceImpl extends AbstractQServiceImpl<RuleGroup> implements RuleGroupService {

    private final RuleGroupDAO ruleGroupDAO;

    private final RuleGroupRelService ruleGroupRelService;

    @Override
    public List<RuleGroup> findByIdCollection(Collection<Long> idCollection) {
        return convertStreamQBeanToList(ruleGroupDAO.findByIdIn(idCollection).stream());
    }

    @Override
    public Optional<RuleGroup> getById(Long id) {
        return ruleGroupDAO.findById(id).map(this::convertQBean);
    }

    @Override
    public Optional<RuleGroup> getByRuleKey(String ruleKey) {
        return ruleGroupDAO.findByRuleKey(ruleKey).map(this::convertQBean);
    }

    @Transactional
    @Override
    public RuleGroup save(RuleGroupCreator creator) throws RuleException {
        // 判断 key 是否已存在, 简单判断, 此业务一般不会并发
        if (StringUtils.isNotEmpty(creator.getRuleKey())) {
            if (ruleGroupDAO.findByRuleKey(creator.getRuleKey()).isPresent()) {
                throw new DataAlreadyExistException("相同key的规则组已存在");
            }
        }
        RuleGroupPO ruleGroupPO = new RuleGroupPO();

        QBeanCreatorHelper.copyCreatorField(ruleGroupPO, creator);

        return convertQBean(ruleGroupDAO.save(ruleGroupPO));
    }

    @Transactional
    @Override
    public RuleGroup update(RuleGroupUpdater updater) throws RuleException {
        RuleGroupPO ruleGroupPO = getEntityWithNullCheckForUpdate(updater.getUpdateId(), ruleGroupDAO);

        if (updater.getRuleKey() != null && !updater.getRuleKey().equals(ruleGroupPO.getRuleKey())) {
            if (ruleGroupDAO.findByRuleKey(updater.getRuleKey()).isPresent()) {
                throw new DataAlreadyExistException("相同key的规则组已存在");
            }
        }

        QBeanUpdaterHelper.copyUpdaterField(ruleGroupPO, updater);

        return convertQBean(ruleGroupPO);
    }

    @Transactional
    @Override
    public void deleteById(Long id) throws RuleException {
        RuleGroupPO ruleGroupPO = getEntityWithNullCheckForUpdate(id, ruleGroupDAO);
        ruleGroupPO.setDeletedTime(System.currentTimeMillis());
    }

    @Override
    public List<RuleGroup> findByRelObjectId(EntityObjectType objectType, Long objectId) {
        // 根据位置的绑定规则对投放进行过滤
        Set<Long> ruleGroupIdSet = ruleGroupRelService.findByObjectId(objectType, objectId)
                .stream()
                .map(RuleGroupRel::getRuleGroupId)
                .collect(Collectors.toSet());
        if (!ruleGroupIdSet.isEmpty()) {
            return findByIdCollection(ruleGroupIdSet);
        }
        return new ArrayList<>();
    }
}
